/**
 * Copyright (C) 2009-2012, KingHool.com
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see http://www.gnu.org/licenses.
 */
package com.kinghool.smodel;

import java.util.List;

import com.kinghool.ebos.commons.Platform;
import com.kinghool.ebos.commons.utils.Assert;
import com.kinghool.ebos.commons.utils.NameHelper;
import com.kinghool.ebos.commons.utils.Utils;
import com.kinghool.smodel.query.Query;

/**
 * 
 * @Author Allen Deng(dengtailin@gmail.com) 
 */
class TreeModelLocator {
	private final static String PARENT_NAME = "..";
	private final static String PROP_START = "{";
	private final static String PROP_END = "}"; 
	private final static String INDEX_START = "[";
	private final static String INDEX_END = "]";
	
	static List<ITreeModel> locateTreeModels(List<ITreeModel> treeModels, String queryStr) {
		if (Assert.isNullOrEmpty(treeModels)) return Utils.newList();
		
		List<ITreeModel> foundTreeModels = Utils.newList();
		foundTreeModels.addAll(treeModels);
		
		List<ITreeModel> srcTreeModels = treeModels;
		if (Assert.isNotNullNotEmpty(queryStr)) {
			for (String name : NameHelper.parseFullName(queryStr)) {
				foundTreeModels.clear();
				
				for (ITreeModel treeModel : srcTreeModels) {
					if (treeModel == null) {
						continue;
					}
					
					if (PARENT_NAME.equals(name)) {
						if (treeModel.getParent() != null && !foundTreeModels.contains(treeModel.getParent())) {
							foundTreeModels.add(treeModel.getParent());
						}
						continue;
					}
					
					if (!validateNameFragment(name, PROP_START, PROP_END, "property criteria") 
						|| !validateNameFragment(name, INDEX_START, INDEX_END, "index criteria")) {
						continue;
					} 
					
					String propertyCriteria = null;
					String indexCriteria = null;
					String formatName = name;
					int nameEndIndex = -1;
					if (name.indexOf(PROP_START) != -1) {
					    propertyCriteria = name.substring(name.indexOf(PROP_START) + 1, name.indexOf(PROP_END));
					    nameEndIndex = nameEndIndex == -1 ? name.indexOf(PROP_START) : 
					    	          (nameEndIndex > name.indexOf(PROP_START) ? name.indexOf(PROP_START) : nameEndIndex);
					}
					if (name.indexOf(INDEX_START) != -1) {
						indexCriteria = name.substring(name.indexOf(INDEX_START) + 1, name.indexOf(INDEX_END));
					    nameEndIndex = nameEndIndex == -1 ? name.indexOf(INDEX_START) : 
			    	                  (nameEndIndex > name.indexOf(INDEX_START) ? name.indexOf(INDEX_START) : nameEndIndex);
					
					}
					if (nameEndIndex != -1) {
						if (nameEndIndex == 0) {
							formatName = "";
						} else {
							formatName = name.substring(0, nameEndIndex);
						}
					}
					
					int index = -1;
					try {
						index = Integer.parseInt(indexCriteria);
					} catch (Exception e) {}
					if (index != -1) {
						ITreeModel foundTreeModel = null;
						if (Assert.isNotNullNotEmpty(formatName)) {
							foundTreeModel = treeModel.getTreeChild(formatName, index, Query.valueOf(propertyCriteria));
						} else {
							foundTreeModel = treeModel.getChild(index, Query.valueOf(propertyCriteria));
						}
						if (foundTreeModel != null) {
							foundTreeModels.add(foundTreeModel);
						}
					} else {
						if (Assert.isNotNullNotEmpty(formatName)) {
							foundTreeModels.addAll(treeModel.getTreeChild(formatName, Query.valueOf(propertyCriteria)));
						} else {
							foundTreeModels.addAll(treeModel.getChild(Query.valueOf(propertyCriteria)));
						}
					}
				}
				
				srcTreeModels.clear();
				srcTreeModels.addAll(foundTreeModels);
			}
		}
		return foundTreeModels;
	} 
	
	static ITreeModel locateFirstTreeModel(ITreeModel treeModel, String queryStr) {
		ITreeModel foundTreeModel = treeModel;
		if (Assert.isNotNullNotEmpty(queryStr)) {
			for (String name : NameHelper.parseFullName(queryStr)) {
				if (foundTreeModel == null) {
					return null;
				}
				
				if (PARENT_NAME.equals(name)) {
					foundTreeModel = foundTreeModel.getParent();
					continue;
				}
				
				if (!validateNameFragment(name, PROP_START, PROP_END, "property criteria") 
					|| !validateNameFragment(name, INDEX_START, INDEX_END, "index criteria")) {
					return null;
				} 
				
				String propertyCriteria = null;
				String indexCriteria = null;
				String formatName = name;
				int nameEndIndex = -1;
				if (name.indexOf(PROP_START) != -1) {
				    propertyCriteria = name.substring(name.indexOf(PROP_START) + 1, name.indexOf(PROP_END));
				    nameEndIndex = nameEndIndex == -1 ? name.indexOf(PROP_START) : 
				    	          (nameEndIndex > name.indexOf(PROP_START) ? name.indexOf(PROP_START) : nameEndIndex);
				}
				if (name.indexOf(INDEX_START) != -1) {
					indexCriteria = name.substring(name.indexOf(INDEX_START) + 1, name.indexOf(INDEX_END));
				    nameEndIndex = nameEndIndex == -1 ? name.indexOf(INDEX_START) : 
		    	                  (nameEndIndex > name.indexOf(INDEX_START) ? name.indexOf(INDEX_START) : nameEndIndex);
				
				}
				if (nameEndIndex != -1) {
					if (nameEndIndex == 0) {
						formatName = "";
					} else {
						formatName = name.substring(0, nameEndIndex);
					}
				}
				
				int index = 0;
				try {
					index = Integer.parseInt(indexCriteria);
				} catch (Exception e) {}
				if (Assert.isNotNullNotEmpty(formatName)) {
					foundTreeModel = foundTreeModel.getTreeChild(formatName, index, Query.valueOf(propertyCriteria));
				} else {
					foundTreeModel = foundTreeModel.getChild(index, Query.valueOf(propertyCriteria));
				}
			}
		}
		return foundTreeModel;
	} 
	
	
	static ITreeModel locateTreeModel(ITreeModel treeModel, 
			                          int parentLevel, 
			                          String childFullName,
			                          Query[] criteria, 
			                          int childIndex) {
		ITreeModel target = null;
		if (treeModel != null) {
			ITreeModel parent = treeModel;
			for (int i = 0; i < parentLevel; i++) {
				parent = parent.getParent();
				if (parent == null) break;
			}
			if (parent != null) {
				if (Assert.isNotNullNotEmpty(childFullName)) {
					return parent.getTreeChild(childFullName, 
							                   childIndex, 
							                   criteria == null ? new Query[0] : criteria);
				} else {
					target = parent;
				}
			}
		}
		return target;
	}
	
	static ITreeModel locateTreeModel(ITreeModel treeModel, 
            int parentLevel, 
            String childFullName,
            Query... criteria) {
		return locateTreeModel(treeModel, 
				               parentLevel, 
				               childFullName, 
				               Assert.isNullOrEmpty(criteria) ? new Query[0] : criteria, 
				               0);
	}
	
	static ITreeModel locateTreeModel(ITreeModel treeModel, int parentLevel) {
		return locateTreeModel(treeModel, 
				               parentLevel, 
				               null, 
				               new Query[0]);
	}
	
	static boolean validateNameFragment(String name, String start, String end, String fragment) {
		if  (name.indexOf(start) != -1) {
			if (name.indexOf(start) != name.lastIndexOf(start)) {
				Platform.getLogManager().warn("Invalid query string: " + fragment + " does not have paired start flag. " + name, Platform.getInstance());
                return false;
			}
			if  (name.indexOf(end) == -1) { 
				Platform.getLogManager().warn("Invalid query string: " + fragment + " does not have end flag. " + name, Platform.getInstance());
                return false;
            }
			if (name.indexOf(end) != name.lastIndexOf(end)) {
				Platform.getLogManager().warn("Invalid query string: " + fragment + " does not have paired end flag. " + name, Platform.getInstance());
                return false;
			}
		}
		return true;
	}
}
